package com.alm.handle.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.alm.common.core.redis.RedisCache;
import com.alm.common.enums.DevUploadDataTypeEnum;
import com.alm.common.enums.YesNotEnum;
import com.alm.entity.*;
import com.alm.handle.core.domain.entity.AlmDataTransmitConfig;
import com.alm.handle.core.domain.entity.SysDevLoginLog;
import com.alm.handle.core.domain.entity.rq.EditEnabledStatusRq;
import com.alm.handle.core.domain.entity.vo.CommonDataVO;
import com.alm.handle.core.domain.entity.vo.CurrentVo;
import com.alm.handle.core.domain.entity.vo.ExCurrentVo;
import com.alm.handle.core.domain.entity.vo.OverloadExDataVO;
import com.alm.handle.mapper.*;
import com.alm.handle.service.*;
import com.alm.handle.util.*;
import com.alm.service.PasEleBusinessService;
import com.alm.service.PasGetWayBusinessService;
import com.alm.service.PasPublicService;
import com.alm.service.SendPubliService;
import com.alm.util.Misc;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.*;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.TimeUnit;

@EnableAsync
//@Async("threadPoolTaskExecutor")
@Service
@Slf4j
public class SocketDataPasingService implements SocketDataPasing {
    private static final Logger logger = LoggerFactory.getLogger(SocketDataPasingService.class);
    public static final String sum = "sum";
    @Autowired
    private RedisCache redisCache;
    @Autowired
    private PasPublicService publicService;
    @Autowired
    private SysDevCurrentDataMapper currentDataMapper;
    @Resource
    private SysDevInfoMapper sysDevInfoMapper;
    @Autowired
    private ISysDevInfoService infoService;
    @Autowired
    private ISysDevCurrentDataService dataService;
    @Autowired
    private PasEleBusinessService eleBusinessService;
    @Autowired
    private ISysDevCurrentData_sService data_sService;
    @Autowired
    private SendPubliService sendPubliService;
    @Resource
    private ISysDevExceptionService devExceptionService;
    @Resource
    private SysDevExceptionMapper exDevMeterCurrentMapper;
    @Resource
    private SysDevLoginLogMapper devLoginLogMapper;
    @Autowired
    private SysAlmEventsLogService eventsLogService;
    @Autowired
    private AlmGetWayDevCurrentDataService getWayDevCurrentDataService;
    @Autowired
    private PasGetWayBusinessService getWayBusinessService;
    @Autowired
    private AlmDevCronService almDevCronService;
    @Autowired
    private SysImgService sysImgService;

    @Resource
    private AlmDataTransmitConfigMapper dataTransmitConfigMapper;

    @Resource
    private DataTransmitService dataTransmitService;

    @Resource
    private RestTemplate restTemplate;



    @Override
    public void login(PasingByteModel.Header header) throws Exception {
        boolean bo=false;
        DevLogin devLogin= publicService.devLogin(header);
        QueryWrapper queryWrapper=new QueryWrapper();
        queryWrapper.eq("device_id",header.getDvcId());
        queryWrapper.select("id");
        if(sysDevInfoMapper.selectOne(queryWrapper)==null){
            infoService.insertDevInfo(header,devLogin);
            dataService.insertDevCurrent(header,devLogin);
        }
        redisCache.setCacheObject(SoketEleKey.ON_LINE+header.getDvcId(),
                "1",60, TimeUnit.SECONDS);
        if (DevTypeUtil.isEleContain(header.getDvcType().byteValue())) {
              bo = dataService.updataSument(header.getDvcId(),devLogin.getDevPowerId()); //更新成功代表是插拔
        }
        //更改一次网络记录
        dataService.updateByNetWorkType(devLogin.getNetWorkType(),header.getDvcId());
        // 持久化一次记录
        dataService.flushPersistenceByMac(header.getDvcId());
        // 是否需要保存
        infoService.updateSaveHisByCache(header.getDvcId());
        updateLineNum(header.getDvcId());//更新插座类型  单路 多路  延迟更新
        // 在线状态
        infoService.updataStatus(header.getDvcId());
        //活动统计数据
        if(bo){
            Integer id= eventsLogService.isnertLog(header.getDvcId(),4);
            eventsLogService.upexistTime(header.getDvcId(),4,id);
        }else{
            Integer id= eventsLogService.isnertLog(header.getDvcId(),1);
            eventsLogService.upexistTime(header.getDvcId(),1,id);
        }
        // 将登录记录存到数据库
        setDataBaseByDevLoginInfo(header, devLogin);
    }

    @Override
    public void updataVersion(PasingByteModel.Header header) {
        String verSion=eleBusinessService.getVersionInfo(header);
        infoService.updateVersion(header.getDvcId(),verSion);
    }

    /**
     * 异常情况获取（掉电）
     * @author: 詹泽峰
     * @date: 2024/7/24 15:32
     * @param header
     * @return void
     */
    @Override
    public void DevEleExUpdate(PasingByteModel.Header header) throws Exception {
        devExceptionService.updateDevExceptionInfo(header);
    }

    @Override
    public void newElectricDataUpdate (PasingByteModel.Header header) throws Exception {
        long st = System.currentTimeMillis();

        Map<String, Object> transmitMap = new HashMap<>(3);
        transmitMap.put("deviceMac", header.getDvcId());

        String key=SoketEleKey.EX_ENERY+header.getDvcId();
        CurrentData currentData = eleBusinessService.singleMeterCurrentNew(header);
        if (currentData.getEx()) {
            //异常信息
            ExDevMeterCurrent ex = currentData.getExDevMeterCurrent();
            ExCurrentVo exCurrentVo=getExvo(ex);
            if(exCurrentVo!=null&&!exCurrentVo.getIsst()){
                //插入异常
                if(!redisCache.hasKey(key)){
                    eventsLogService.isnertLog(header.getDvcId(),3,exCurrentVo.getMsg());
                }
                redisCache.setCacheObject(key,exCurrentVo.getMsg(),60,TimeUnit.SECONDS);

                OverloadExDataVO vo = new OverloadExDataVO();
                BeanUtils.copyProperties(ex, vo);
                transmitMap.put("dataType", DevUploadDataTypeEnum.OVERLOAD.name());
                transmitMap.put("overloadExDataVO", vo);
            }
        } else {
            if(redisCache.hasKey(key)){
                eventsLogService.upexistTime(header.getDvcId(),5,0);
                redisCache.deleteObject(key);
            }
            //正常信息
            DevMeterCurrent current = currentData.getDevMeterCurrent();
            current.calculate();

            CurrentVo currentVo = dataService.upDateCurrent(current);

            CommonDataVO commonDataVO = new CommonDataVO();
            // 加工数据
            processCommonDataBean(currentVo, commonDataVO);
            transmitMap.put("dataType", DevUploadDataTypeEnum.COMMON.name());
            transmitMap.put("commonDataVO", commonDataVO);

        }
        // 转发
        log.info("Obj：{}", transmitMap.get("commonDataVO"));
        List<AlmDataTransmitConfig> configList = dataTransmitConfigMapper.selectList(new QueryWrapper<AlmDataTransmitConfig>().lambda()
                .eq(AlmDataTransmitConfig::getIsEnabled, YesNotEnum.Y.getCode()));
        if(configList != null && configList.size() > 0) {
            AlmDataTransmitConfig transmitConfig = configList.get(0);
            dataTransmitService.sendTransmitData(transmitMap, transmitConfig);
        }

        long end = System.currentTimeMillis();
        log.info("发送请求执行耗时：{} ms", (end-st) );

    }


    /**
     * 正常数据加工
     * @param currentVo
     * @param vo
     */
    private void processCommonDataBean(CurrentVo currentVo, CommonDataVO vo){

        BeanUtils.copyProperties(currentVo, vo);
        vo.setEnergy(currentVo.getEnergy() != null ? new BigDecimal(currentVo.getEnergy()).setScale(3, BigDecimal.ROUND_CEILING) : new BigDecimal(0));
        vo.setVoltage(currentVo.getVoltage() != null ? new BigDecimal(currentVo.getVoltage()).setScale(2, BigDecimal.ROUND_CEILING) : new BigDecimal(0));
        vo.setActivePower(currentVo.getActivePower() != null ? new BigDecimal(currentVo.getActivePower()).setScale(3, BigDecimal.ROUND_CEILING) : new BigDecimal(0));
        vo.setCurrentElectric(currentVo.getCurrent() != null ? new BigDecimal(currentVo.getCurrent()).setScale(3, BigDecimal.ROUND_CEILING) : new BigDecimal(0));
        vo.setFrequency(currentVo.getFrequency() != null ? new BigDecimal(currentVo.getFrequency()).setScale(2, BigDecimal.ROUND_CEILING) : new BigDecimal(0));
        vo.setPowerFactor(currentVo.getPowerFactor() != null ? new BigDecimal(currentVo.getPowerFactor()).setScale(2, BigDecimal.ROUND_CEILING) : new BigDecimal(0));

    }

    /**
     * 多路数据处理
     * @param devMeterCurrentMap
     * @return
     */
    @Override
    public boolean moreLineDataParsing(Map<String, DevMeterCurrent> devMeterCurrentMap) {

        for (String key : devMeterCurrentMap.keySet()) {
            if (key.equals("sum")) {
                continue;
            }
            DevMeterCurrent data=devMeterCurrentMap.get(key);
            data_sService.upDateCurrent_s(data);
        }
        // 更新总的
        data_sService.upSumDataCurrent(devMeterCurrentMap.get("sum"));
        return true;
    }


    /**
     * 根据指令类型处理业务
     * @param header
     * @param ctxid
     * @throws Exception
     */
    @Async("threadPoolTaskExecutor")
//    @Async
    @Override
    public void pasingData(PasingByteModel.Header header, String ctxid) throws Exception {
        int switchd = header.getIntData().get(4); //指令类型
        logger.info("指令类型 = {}", Misc.int2hexStr2(switchd));

        // 如果是网关
        if (DevTypeUtil.isGetWayContain(header.getDvcType().byteValue())) {
            switch (switchd) {
                case 1:
                    getWayDevCurrentDataService.getWaylogin(header);
                    break;
                case 0x03:
                    GetWayUpLoadData getWayUpLoadData=   getWayBusinessService.dealUploadData(header);

                    logger.info("getWayUpLoadData={}", getWayUpLoadData.toString());

                    getWayDevCurrentDataService.pasingGetWayData(header.getDvcId(),getWayUpLoadData);
                    break;
                case 0xA0:
                    getWayDevCurrentDataService.deal_lable(header);
                    break;
//                default:
//                    getWayDevCurrentDataService.pasingGetWayData(header.getDvcId(),new GetWayUpLoadData());
//                    break;
                default:
            }
        }
        // 如果是插座
        else  if (DevTypeUtil.isEleContain(header.getDvcType().byteValue())) {
            switch (switchd) {
                case 4:
                    //时间同步
                    if(!publicService.timeCorrection(header, 1000000L)){//未同步成功
                        byte [] data=sendPubliService.sendTimeCorrection(System.currentTimeMillis(),
                                1,header);
                        //将data发送给设备
                        System.out.println("同步未成功");
                        SendMessage.sendMessage(data, header.getDvcId().toUpperCase());
                    } else {
//                        byte[] data = sendPubliService.sendTimeCorrection(System.currentTimeMillis(),
//                                1, header);
                        //将data发送给设备
                        System.out.println("同步成功");
//                        SendMessage.sendMessage(data, header.getDvcId().toUpperCase());
                    }
                    break;
                case 0x03:
                    Map<String, DevMeterCurrent> duolinMap = eleBusinessService.moreLineDataParsing(header);
                    if (duolinMap == null) {
                        newElectricDataUpdate(header);
                    } else {
                        moreLineDataParsing(duolinMap);
                    }
                    break;
                case 0xB4:
                    almDevCronService.updateRedisCronList(header);
                    break;
                case 0xA1:
                    sysImgService.sendImgData(header);
                    break;
                case 0x30:
                    //异常数据
                    DevEleExUpdate(header);
                    break;
                case 0x01:
                    byte[] data = sendPubliService.sendTimeCorrection(System.currentTimeMillis(),
                            0, header);
                    //将data发送给设备
                    SendMessage.sendMessage(data, header.getDvcId());
                    login(header);
                    System.out.println("登录成功");
                    //查看是否有分组定时任务，有则添加
                    almDevCronService.addCronWhenLogin(header.getDvcId(), header.getDvcType());
                    break;
                case 0x32:
                    //绑定
                    String bindName = eleBusinessService.bindDev(header);
                    infoService.bindName(header.getDvcId(), bindName);
                    break;
                case 0x33:
                    //解绑

                    break;
                case 0xC0:
                    Integer id=header.getIntData().get(6);
                    if(id==0x79){
                        int this_page=Integer.parseInt(ByteUtils.arrayToString(header.getIntData(),7,9),16);
                        int status=header.getIntData().get(10);
                        if(status==0x09){
                            //发送下一包
                           byte [] bytes= dataService.get4GSliceUpData(header.getDvcId(),"",this_page);
                           SendMessage.sendMessage(bytes,header.getDvcId());
                        }else {
                            logger.info("切片固件升级失败，代码为:{}",status);
                        }
                    }
                    break;
                default:
            }
        }

    }
    // 更新设备是单路还是多路
    void  updateLineNum(String devMac){
        Timer timer = new Timer();
        TimerTask task = new TimerTask() {
            @Override
            public void run() {
                dataService.updateLineNum(devMac,timer);
            }
        };
        // 20秒后执行任务
        timer.schedule(task, 20000);
    }

    void setDataBaseByDevLoginInfo(PasingByteModel.Header header, DevLogin devLogin) {
        // 如果当前上电id和最后一次上电id相同，不插入数据
        SysDevLoginLog loginLog = devLoginLogMapper.selectOne(new QueryWrapper<SysDevLoginLog>().lambda()
                .eq(SysDevLoginLog::getDvcId, header.getDvcId())
                .eq(SysDevLoginLog::getRouterMac, devLogin.getRouterMac())
                .orderByDesc(SysDevLoginLog::getLoginTime)
                .last("limit 1"));

        if(loginLog != null && loginLog.getDevPowerId().equals(devLogin.getDevPowerId())) {
            return;
        }

        SysDevLoginLog sysDevLoginLog = new SysDevLoginLog();
        sysDevLoginLog.setLoginTime(System.currentTimeMillis());
        sysDevLoginLog.setDvcId(header.getDvcId());
        sysDevLoginLog.setDvcType(header.getDvcType());
        sysDevLoginLog.setTime(header.getTime());
        sysDevLoginLog.setDevPowerId(devLogin.getDevPowerId());
        sysDevLoginLog.setRouterMac(devLogin.getRouterMac());
        devLoginLogMapper.insert(sysDevLoginLog);
    }
    private ExCurrentVo getExvo(ExDevMeterCurrent ex){
        if(ex.getExActivePower()!=null&&ex.getExActivePower()>0L){
            return new ExCurrentVo(false,"异常功率");
        }

        if(ex.getExEnergy()!=null&&ex.getExEnergy()>0L){
            return new ExCurrentVo(false,"异常电流");
        }

        if(ex.getExVoltage()!=null&&ex.getExVoltage()>0L){
            return new ExCurrentVo(false,"异常电压");
        }

        if(ex.getExElectricCurrent()!=null&&ex.getExElectricCurrent()>0L){
            return new ExCurrentVo(false,"异常电流");
        }

        if(ex.getStExEnergy()!=null&&ex.getStExEnergy()>0L){
            return new ExCurrentVo(true,"瞬态电流",ex.getStExEnergy());
        }

        if(ex.getStexVoltage()!=null&&ex.getStexVoltage()>0L){
            return new ExCurrentVo(true,"瞬态电压",ex.getStExEnergy());
        }

        return null;
    }

}
